package uid

import (
	"sync"
	"time"
)

var (
	defaultMachine UidMachine
	defaultOnce    sync.Once
	timeNowHander  func() time.Time
)

// Default 获取默认UidMachine工作机
// 默认参数:
//   - DefaultDateMixBit 20
//   - DefaultworkerBit 5
//   - DefaultSequenceBit 11
//   - DefaultWorkerID 0
//   - DefaultbaseZipDays 2023001
func Default() UidMachine {
	if defaultMachine == nil {
		defaultOnce.Do(func() {
			machine, err := NewUidMachine(DefaultDateMixBit, DefaultworkerBit, DefaultSequenceBit, DefaultWorkerID, DefaultbaseZipDays)
			if err != nil {
				panic(err)
			}
			defaultMachine = machine
		})
	}
	return defaultMachine
}

// SetDefault 替换默认的UidMachine工作机
func SetDefault(um UidMachine) {
	if um != nil {
		defaultMachine = um
	}
}

// NextID 通过默认生成器生成一个新的UID
//   - 返回值是int64类型的UID
func NextID() int64 {
	return Default().NextID()
}

// GetWorkerID 获取默认生成器工作机ID
func GetWorkerID() int64 {
	return Default().GetWorkerID()
}

// GetWorkerMax 获取默认生成器工作机最大值
func GetWorkerMax() int64 {
	return Default().GetWorkerMax()
}

// GetSequenceMax 获取默认生成器工作机自增序列位最大值
func GetSequenceMax() int64 {
	return Default().GetSequenceMax()
}

// GetLastTimestamp 获取默认生成器工作机运行时时间戳(毫秒)
func GetLastTimestamp() int64 {
	return Default().GetLastTimestamp()
}

// SetWorkerID 设置默认生成器当前工作机ID，通常用于处理时间回拨故障，切换到互备工作机ID
func SetWorkerID(id int64) error {
	return Default().SetWorkerID(id)
}

// SetLastTimestamp 设置默认生成器当前工作机运行时时间戳(毫秒), 通常用于处理时间回拨故障，当服务器(工作机)重新启动时，设置上次运行时间回拨故障时最后的时间戳
func SetLastTimestamp(ts int64) error {
	return Default().SetLastTimestamp(ts)
}

// Parse 解析默认生成器UID信息
//
//	注意:
//	- 未发生时间回拨，解析出来的时间信息ID是创建的时间信息
//	- 如发生时间回拨，解析出来的时间信息是发生回拨时逻辑时间信息
func Parse(uid int64) (uidInfo *UidInfo, err error) {
	return Default().Parse(uid)
}

// SetTimeHander 自定义当前时间获取接口(范围: 全局)
//
//	Default timeNowHander() time.Time{
//		return time.Now().UTC()
//	}
func SetTimeNowHander(hander func() time.Time) {
	timeNowHander = hander
}
func getNowTime() *time.Time {
	var now time.Time
	if timeNowHander == nil {
		now = time.Now().UTC()
		return &now
	}
	now = timeNowHander()
	if now.IsZero() {
		now = time.Now().UTC()
	} else if now.Location() != time.UTC {
		now = now.In(time.UTC)
	}
	return &now
}
